package 多线程.多线程同步的5种方法;

/**
 * @date 2017/8/31.
 * @author 廖述京
 * @result 可以发现，两个线程操作同一个账户时(存取)，导致账户异常！
 */
public class ThreadTest {
    public static void main(String args[]){
        //1、没有同步的账户测试
//        final NoSyncBank bank=new NoSyncBank();
        //2、同步存取方法的账户测试 (synchronized关键字，时间换空间)--锁方法
//        final SyncMethod_Bank bank=new SyncMethod_Bank();
        //3、同步存取代码块的账户测试 (synchronized关键字，时间换空间)--锁对象
//        final SyncCode_Bank bank=new SyncCode_Bank();
        //4、ReentrantLock锁类的账户测试 (ReentrantLock开锁解锁和synchronized关键字效果一样，一般用后者，因为简单，同时不会有死锁危机)
//        final ReentrantLock_Bank bank=new ReentrantLock_Bank();

        //5-6账户仍然有安全问题：
        //5、volatile变量的账户测试 (volatile关键字，每次访问内存中的值)
//        final VolatileVar_Bank bank=new VolatileVar_Bank(); //不能保证线程安全，因为volatile关键字只是用来保证变量安全的
        //6、ThreadLocal局部变量的账户测试 (ThreadLocal类，每一个使用该变量的线程都获得该变量的一个独立副本)---空间换时间
//        final ThreadLocal_Bank bank=new ThreadLocal_Bank();  //因为存钱和取钱使用的是两个线程，
              // ThreadLocal给分配了两个不同的副本，这相当于存钱和取钱是两个账户！

        //7、原子变量的账户测试 (原子操作保证读取、操作、写回这一整体同成功或失败)
        final AtomicInteger_Bank bank=new AtomicInteger_Bank();

        //存100
        Thread tadd=new Thread(new Runnable() {
            @Override
            public void run() {
                while(true){ //持续存
                    try {
                        Thread.sleep(1000); //线程休眠1s
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    bank.addMoney(100);
                    bank.lookMoney();
                    System.out.println();

                }
            }
        });

        //取100
        Thread tsub = new Thread(new Runnable() {
            @Override
            public void run() {
                while(true){ //持续取
                    bank.subMoney(100);
                    bank.lookMoney();
                    System.out.println();
                    try {
                        Thread.sleep(1000); //线程休眠4s
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        });
        tsub.start(); //启动取钱线程
        tadd.start(); //启动存钱线程
    }
}
